// Metgine/Core/Vector2.h
//
// Copyright 2011 Phillip Stephens
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.

#ifndef __VECTOR2_H__
#define __VECTOR2_H__

#include <SFML/System/Vector2.hpp>
#include <Metgine/Config.h>
#include <Metgine/Core/Math.h>

namespace Metgine
{
namespace Core
{

template <class T>
struct METGINE_API Vector2
{

    T x, y;

    Vector2() { x = y = 0; };
    Vector2(T X, T Y) { x = X; y = Y; };
    Vector2(sf::Vector2f v) { x = v.x; y = v.y; };
    Vector2(sf::Vector2i v) { x = v.x; y = v.y; };

    Vector2& operator = (const Vector2& v)
    {

        if (this != &v)
        {

            x = v.x;
            y = v.y;

        }

        return *this;

    }

    Vector2& operator *= (T f)
    {

        x *= f;
        y *= f;

        return *this;

    }

    Vector2& operator /= (T f)
    {

        x /= f;
        y /= f;

        return *this;

    }

    Vector2& operator += (const Vector2& v)
    {

        x += v.x;
        y += v.y;

        return *this;

    }

    Vector2& operator -= (const Vector2& v)
    {

        x -= v.x;
        y -= v.y;

        return *this;

    }

    Vector2 operator + (const Vector2& v)
    {

        Vector2 result = *this;
        result += v;

        return result;

    }

    Vector2 operator - (const Vector2& v)
    {

        Vector2 result = *this;
        result -= v;

        return result;
    }

    Vector2 operator - ()
    {

        Vector2 v = *this;
        v.x = -v.x;
        v.y = -v.y;

        return v;

    }

    Vector2 operator * (T f)
    {

        Vector2 result = *this;
        result *= f;

        return result;

    }

    Vector2 operator / (T f)
    {

        Vector2 result = *this;
        result /= f;

        return result;

    }

    inline float LengthSquared()
    {

        return x * x + y * y;

    }

    inline float Length()
    {

        return Math::Sqrt(LengthSquared());

    }

    Vector2<float> Normalize()
    {

        float lengthSquared = LengthSquared();

        if (lengthSquared > Math::EPSILON)
        {

            float length = Math::Sqrt(lengthSquared);
            return Vector2<float>(x / length, y / length);

        }

        return Vector2<float>(x, y);

    }

    Vector2 Perpendicular()
    {

        return Vector2(-y, x);

    }

    sf::Vector2<T> ToSF()
    {

        return sf::Vector2<T>(x, y);

    }

};

//
// Predefined types
//

typedef Vector2<float>        Vector2f;
typedef Vector2<int>        Vector2i;

//
// Methods
//

template <class T>
inline float DotProduct(const Vector2<T>& a, const Vector2<T>& b)
{

    return a.x * b.x + a.y * b.y;

}

//
// Operators
//

template <class T>
inline Vector2<T> operator + (const Vector2<T>& a, const Vector2<T>& b)
{

    return Vector2<T>(a.x + b.x, a.y + b.y);

}

template <class T>
inline Vector2<T> operator - (const Vector2<T>& a, const Vector2<T>& b)
{

    return Vector2<T>(a.x - b.x, a.y - b.y);

}

template <class T>
inline Vector2<T> operator * (const Vector2<T>& v, float f)
{

    return Vector2<T>(v.x * f, v.y * f);

}

template <class T>
inline Vector2<T> operator / (const Vector2<T>& v, float f)
{

    return Vector2<T>(v.x / f, v.y / f);

}

// Returns true if a vector is finite
inline bool IsFinite(const Vector2f& v)
{

    return ((Math::IsFinite(v.x)) && (Math::IsFinite(v.y)));

}

}; // Core
}; // Metgine
#endif // VECTOR2_H_
